package br.edu.catolica.sadbc.core.util;

import java.util.StringTokenizer;

public class Soundex {

    private static String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVXZWY ";
    
    private static String[] PREPOSITIONS = {"DOS", "DE", "DA", "DAS", "DO", "E",
    	                                    "A", "AO", "ANTE", "APOS", "ATE", "COM",
    	                                    "CONTRA", "DESDE", "EM", "ENTRE", "PARA",
    	                                    "PERANTE", "POR", "SEM", "SOB", "SOBRE", "TRAS"};

    public static String convertSound(String s) {
    	if (s != null) {
	        String s1 = s.replaceAll("PH", "F");
	        s1 = s1.replaceAll("SCH", "X");
	        s1 = s1.replaceAll("SH", "X");
	        s1 = s1.replaceAll("CH", "X");
	        s1 = s1.replaceAll("Y", "I");
	        s1 = s1.replaceAll("Ç", "S");
	        s1 = s1.replaceAll("GE", "JE");
	        s1 = s1.replaceAll("GI", "JI");
	        s1 = s1.replaceAll("QUE", "KE");
	        s1 = s1.replaceAll("QUI", "KI");
	        s1 = s1.replaceAll("KL", "CL");
	        s1 = s1.replaceAll("KR", "CR");
	
	        if (s1.startsWith("H")) {
	            s1 = s1.replaceFirst("H", "");
	        }
	
	        if (s1.startsWith("CE")) {
	            s1 = s1.replaceFirst("CE", "SE");
	        }
	
	        if (s1.startsWith("CI")) {
	            s1 = s1.replaceFirst("CI", "SI");
	        }
	
	        if (s1.startsWith("KA")) {
	            s1 = s1.replaceFirst("K", "C");
	        }
	
	        if (s1.startsWith("WA")) {
	            s1 = s1.replaceFirst("W", "V");
	        }
	
	        if (s1.startsWith("WI")) {
	            s1 = s1.replaceFirst("W", "U");
	        }
	
	        if (s1.startsWith("WE")) {
	            s1 = s1.replaceFirst("W", "U");
	        }
	
	        s1 = s1.replaceAll("W", "V");
	
	        return s1;
    	}
    	return null;
    }

    // remove acentuacao
    public static String removeMarks(String s) {
        char inArray[] = s.toCharArray();
        for (int i = 0; i < inArray.length; i++) {
            //201,202,203,193,192,194,195,196,199,205,211,213,212,214,218,220,209
            switch (inArray[i]) {
                case 201:
                    inArray[i] = 'E'; // É -> E
                    break;
                case 202:
                    inArray[i] = 'E'; // Ê -> E
                    break;
                case 203:
                    inArray[i] = 'E'; // Ë -> E
                    break;
                case 193:
                    inArray[i] = 'A'; // Á -> A
                    break;
                case 192:
                    inArray[i] = 'A'; // À -> A
                    break;
                case 194:
                    inArray[i] = 'A'; // Â -> A
                    break;
                case 195:
                    inArray[i] = 'A'; // Ã -> A
                    break;
                case 196:
                    inArray[i] = 'A'; // Ä -> A
                    break;
                case 199:
                    inArray[i] = 'C'; // Ç -> C
                    break;
                case 205:
                    inArray[i] = 'I'; // Í -> I
                    break;
                case 211:
                    inArray[i] = 'O'; // Ó -> O
                    break;
                case 213:
                    inArray[i] = 'O'; // Õ -> O
                    break;
                case 212:
                    inArray[i] = 'O'; // Ô -> O
                    break;
                case 214:
                    inArray[i] = 'O'; // Ö -> O
                    break;
                case 218:
                    inArray[i] = 'U'; // Ú -> U
                    break;
                case 220:
                    inArray[i] = 'U'; // Ü -> U
                    break;
                case 209:
                    inArray[i] = 'N'; // Ñ -> N
                    break;
            }
        }
        s = String.copyValueOf(inArray).trim();
        return s;
    }

    public static String soundexFirstAndLastToken(String s) {
        String result = new String();
        StringTokenizer parser = new StringTokenizer(s);

        s = parser.nextToken();
        result += soundexString(s);

        do {
            s = parser.nextToken();
        } while (parser.hasMoreTokens());

        result += soundexString(s);

        return result;
    }

    public static String soundexString(String value) {
    	String s = null;
    	
        if (value == null) {
            return "";
        }
        
        // Passa todas as letras para maíusculo
        s = value.toUpperCase();

        // Remove os acentos das vogais
        s = removeMarks(s);

        // Remove as preposicoes
        s = removePrepositions(s);

        // Remove os caractéres inválidos
        s = removeInvalidChar(s);

        // Converte as letras para fonema respectivo
        s = convertSound(s);
        
        if (s == null || s.trim().equals("")) {
            return "";
        }

        char[] x = s.toCharArray();
        char firstLetter = x[0];

        // converte as letras para um codigo numerico
        for (int i = 0; i < x.length; i++) {
            switch (x[i]) {
                case 'B':
                case 'F':
                case 'P':
                case 'V': {
                    x[i] = '1';
                    break;
                }

                case 'C':
                case 'G':
                case 'J':
                case 'K':
                case 'Q':
                case 'S':
                case 'X':
                case 'Z': {
                    x[i] = '2';
                    break;
                }

                case 'D':
                case 'T': {
                    x[i] = '3';
                    break;
                }

                case 'L': {
                    x[i] = '4';
                    break;
                }

                case 'M':
                case 'N': {
                    x[i] = '5';
                    break;
                }

                case 'R': {
                    x[i] = '6';
                    break;
                }

                case 'A': {
                    x[i] = '7';
                    break;
                }

                case 'E':
                case 'I': {
                    x[i] = '8';
                    break;
                }

                case 'O':
                case 'U': {
                    x[i] = '9';
                    break;
                }

                default: {
                    x[i] = '0';
                    break;
                }
            }
        }

        // remove caracteres duplicados
        String output = "" + firstLetter;
        char last = x[0];
        for (int i = 1; i < x.length; i++) {
            if (x[i] != '0' && x[i] != last) {
                last = x[i];
                output += last;
            }
            // output += x[i];
        }

        return output;
    }

    public static String removePrepositions(String s) {
        StringTokenizer parser = new StringTokenizer(s.toUpperCase());
        
        String result = null;
        if (s != null && !s.trim().equals("")) {
	        while (parser.hasMoreTokens()) {
				String word = parser.nextToken();
				if (!isPreposition(word)) {
					if (result == null) {
						result = "";
					}
					
					if (result.length() > 0) {
						result += " ";
					}
					
					result += word;
				}
			}
        }
        
        return result;
    }

    // testa se e preposição
    private static boolean isPreposition(String palavra) {
        for (int i = 0; i < PREPOSITIONS.length; i++) {
			if (palavra.equals(PREPOSITIONS[i])) {
				return true;
			}
		}

        return false;
    }

    private static String removeInvalidChar(String s) {
        if (s == null) {
            return null;
        }

        if (s.trim().equals("")) {
            return "";
        }

        char c[] = s.toCharArray();
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < c.length; i++) {
            boolean achou = false;
            for (int j = 0; j < ALPHABET.length(); j++) {
                if (c[i] == ALPHABET.charAt(j)) {
                    achou = true;
                }
            }

            if (achou) {
                sb.append(c[i]);
            }
        }

        return sb.toString();
    }

    public static String soundexTokens(String s) {
        return soundexTokens(s, false);
    }

    public static String soundexTokens(String s, boolean isFirstAndLast) {

        if (s == null || s.trim().equals("")) {
            return null;
        }

        String name = new String();
        String soudexResult = new String();

        StringTokenizer parser = new StringTokenizer(s.toUpperCase());
        int countTokens = parser.countTokens();

        do {
            name = parser.nextToken();
            if (!isPreposition(name)) {
                if (name.length() < 2) {
                    countTokens--;
                    continue;
                }
                soudexResult += soundexString(name);
            }
        } while (parser.hasMoreTokens());

        // Acrescenta primeiro e último tiver mais de dois nomes
        if (countTokens > 2 && isFirstAndLast) {
            soudexResult += soundexFirstAndLastToken(s);
        }

        return soudexResult;
    }
    
    public static String[] soundexArray(String s) {
    	String value = removePrepositions(s);
    	
    	String[] output = null;
        if (value != null && !value.trim().equals("")) {
        	StringTokenizer parser = new StringTokenizer(value);
        	
        	output = new String[parser.countTokens()];
        	int i = 0;
        	while (parser.hasMoreTokens()) {
				String token = parser.nextToken();
				output[i] = soundexString(token);
				i++;
			}
        }
    	return output;
    }
}

